<template>
  <div class="choose-btn" @click="upload()">+</div>
</template>

<script>
export default {
  props: {
    size: {
      type: Number,
      default: 0,
    },
    uploadBefore: {
      type: Function,
      default: () => {},
    },
    onlyCamera: {
      // 移动端才起作用
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      targetSize: this.size,
      files: [],
      input: null,
    };
  },
  methods: {
    createInput() {
      var input = document.createElement("input");
      input.setAttribute("multiple", true);
      // input.setAttribute('accept','image/*');
      input.type = "file";
      input.accept = "image/*";
      if (this.onlyCamera) {
        input.capture = "camera";
      }
      //选完图片后触发
      input.onchange = (event) => {
        // uni.showLoading();
        let files =
          (event.target && event.target.files) ||
          input.files ||
          event.path[0].files;
        files = [...files];
        //目前只能单选一张图
        files.forEach(async (item) => {
          let base64, file;
          file = item;
          this.targetSize = this.size || file.size;
          base64 = await this.compressImg(file);
          file = this.base64ToFile(base64, item.name);
          this.files.push({ file, fileName: item.name, filePath: base64 }); //将压缩后的图片base64再转成file
        });
        this.$emit("uploadSuccess", this.files);
      };
      //this.$refs.box.$el.appendChild(input);
      return input;
    },
    upload() {
      let res = this.uploadBefore();
      if (res === false) {
        return;
      }
      this.files = [];
      this.input = this.createInput(); // 每次都创建一个新的input，目的是为了防止删掉图片后再选择相同的图片不触发input.onchange
      this.input.click();
    },
    // 压缩图片核心方法
    compressImg(file) {
      var that = this;
      var read = new FileReader();
      read.readAsDataURL(file);
      var sizeAfterCompress = file.size;
      return new Promise(function (resolve, reject) {
        read.onload = function (e) {
          var img = new Image();
          img.src = e.target.result;
          img.onload = async function () {
            var aspectRatio = img.width / img.height; //横纵比
            var base64 = await that.fileToBase64(file); // 默认值
            var unit = parseInt(img.width / 20); // 单位像素减少值，默认按1/30
            let multiple = 2; // 压缩后比目标大小的倍数，压缩后如果图片比目标这个倍数还大，就不再减少质量，而直接降低分辨率
            if (sizeAfterCompress > 10 * 1024 * 1024) {
              // 大于10M的图片按1/10
              unit = parseInt(img.width / 5);
              multiple = 4;
            } else if (sizeAfterCompress > 5 * 1024 * 1024) {
              // 大于5M的图片按1/20
              unit = parseInt(img.width / 10);
              multiple = 3;
            }
            var sub_px = unit;
            // 如果大小没有小于规定的大小，就继续修改分辨率压缩
            while (sizeAfterCompress > that.targetSize && sub_px < img.width) {
              //保持图片原来的比例
              var w = img.width - sub_px; // 这里如果想提高效率，w可以使用二分算法来代替，不过只是单纯二分的话可能会出现图片压缩过度，目前只是想压缩的更接近目标值。
              var h = parseInt(w / aspectRatio);
              //生成canvas
              var canvas = document.createElement("canvas");
              var ctx = canvas.getContext("2d");
              // 创建属性节点
              canvas.setAttribute("width", w);
              canvas.setAttribute("height", h);
              ctx.drawImage(img, 0, 0, w, h);
              var quality = 0.8;
              // 在一定分辨率下调至图片质量
              while (sizeAfterCompress > that.targetSize && quality >= 0.2) {
                base64 = canvas.toDataURL("image/jpeg", quality);
                // 转成file，获取size
                sizeAfterCompress = that.base64ToFile(base64).size;
                // console.log((sizeAfterCompress / 1024).toFixed(2) + "k"); // 压缩后大小
                quality = quality - 0.1;
                if (sizeAfterCompress > that.targetSize * multiple) {
                  // 如果首次压缩大于目标值的5倍，则直接跳出，换更小的分辨率继续压缩
                  break;
                }
              }
              sub_px += unit;
            }
            resolve(base64); //这里直接返回base64
          };
        };
      });
    },
    dataURLtoBlob(dataurl) {
      // base64->blob
      var arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], { type: mime });
    },
    blobToFile(theBlob, fileName) {
      // blob->file
      theBlob.lastModifiedDate = new Date();
      theBlob.name = fileName;
      return theBlob;
    },
    base64ToFile(base64Data, imgName) {
      // base64->file
      var blob = this.dataURLtoBlob(base64Data);
      return this.blobToFile(blob, imgName);
    },
    base64ToFile2(dataurl, filename = "file") {
      // base64转file对象
      var arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1];
      let suffix = mime.split("/")[1];
      let bstr = atob(arr[1]);
      let n = bstr.length;
      let u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename + "." + suffix, { type: mime });
    },
    fileToBase64(file) {
      // file->base64
      var reads = new FileReader();
      reads.readAsDataURL(file);
      return new Promise(function (resolve, reject) {
        reads.onload = async function (e) {
          resolve(this.result);
        };
        reads.onerror = function (e) {
          reject(e);
        };
        reads.onloadend = function (e) {
          // 不管成功失败都会执行
          //uni.hideLoading()
        };
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.choose-btn {
  width: 100px;
  height: 100px;
  border: 1px dashed #ccc;
  border-radius: 10px;
  text-align: center;
  line-height: 100px;
  font-size: 30px;
  font-weight: 100;
}
</style>
